home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 12 - 1996 / 12.03 Mar 96 / 12.03 Tips & Tidbits < prev    next >
Encoding:
Text File  |  1996-01-30  |  10.3 KB  |  387 lines  |  [TEXT/R*ch]

  1. Calling PowerPC Code 
  2.        From 68K Code
  3. There is a lot of information out there about calling 68K code from PowerPC
  4. code, but there is very little about calling PowerPC code from 68K code.
  5. Here is a nice method for calling PowerPC code from 68K code. I am using
  6. CodeWarrior 7.  This is a bit lengthy so hang in there:
  7. There are three steps required to get things up and running.  Let’s look at a
  8. sample scenario:
  9. You have a 68K application that you just can’t convert to PowerPC code (I don’t
  10. know why you can’t convert it, but just bear with me), but you can take some of
  11. the time-critical code and convert it to a PowerPC shared library and call it
  12. from the 68K code.
  13. Suppose you have two functions that perform data compression:
  14.         
  15. long    CompressData(     unsigned char *inBuffer, 
  16.                                     unsigned char *outBuffer,
  17.                                     unsigned long inBufferSize );
  18.                               
  19. long    UncompressData(    unsigned char *inBuffer, 
  20.                                     unsigned char *outBuffer, 
  21.                                     unsigned long inBufferSize );
  22.  
  23. Step 1 – Create a PPC shared library containing your functions.
  24. We are going to export these functions using the #pragma export directive. 
  25. This is set in the PPC Prefs area of Codewarrior preferences.
  26.  
  27. “the shared library”
  28. // Prototypes
  29.  
  30. #pragma export on
  31.  
  32. #ifdef __cplusplus
  33. extern "C" {
  34. #endif
  35.  
  36. long    CompressData(     unsigned char    *inBuffer, 
  37.                                 unsigned char    *outBuffer, 
  38.                                 unsigned long inBufferSize );
  39.                       
  40. long    UncompressData(     unsigned char *inBuffer,
  41.                                         unsigned char *outBuffer,
  42.                                         unsigned long inBufferSize );
  43.  
  44. #ifdef __cplusplus
  45. }
  46. #endif
  47.  
  48. #pragma export off
  49. // CompressData
  50.  
  51. long    CompressData( unsigned char *inBuffer, unsigned char 
  52.                       *outBuffer, unsigned long inBufferSize )
  53. {
  54.     ... compress data code
  55. }
  56.  
  57. // UncompressData
  58.                       
  59. long    UncompressData( unsigned char *inBuffer, unsigned char 
  60.                         *outBuffer, unsigned long inBufferSize )
  61. {
  62.     ... uncompress data code
  63. }
  64. Set the project type to a shared library and build the project. We now have a
  65. PowerPC shared library that we will use in Step 2.
  66.  
  67. Step 2 – Create a resource-based PEF Fragment that references our shared
  68. library.
  69. We create a header file that defines some mixed mode information.
  70.  
  71. “the header file”
  72. #ifdef __cplusplus
  73. extern "C" {
  74. #endif
  75.  
  76. typedef long (*CompressDataProcPtr)( unsigned char *inBuffer, 
  77.             unsigned char *outBuffer, unsigned long inBufferSize );
  78. typedef long (*UncompressDataProcPtr)( unsigned char *inBuffer, 
  79.             unsigned char *outBuffer, unsigned long inBufferSize);
  80.  
  81. #if GENERATINGCFM || USESROUTINEDESCRIPTORS
  82.  
  83. typedef UniversalProcPtr CompressDataUPP;
  84. typedef UniversalProcPtr UncompressDataUPP;
  85.  
  86. enum {
  87.     uppCompressDataProcInfo = kCStackBased
  88.         | RESULT_SIZE( SIZE_CODE( sizeof( long ) ) )
  89.         | STACK_ROUTINE_PARAMETER( 1, SIZE_CODE( 
  90.                                                             sizeof( unsigned
  91. char *) ) )
  92.         | STACK_ROUTINE_PARAMETER( 2, SIZE_CODE( 
  93.                                                             sizeof( unsigned
  94. char *) ) )            | STACK_ROUTINE_PARAMETER( 3, SIZE_CODE( 
  95.                                                             sizeof( long ) ) )
  96. };
  97.  
  98. enum {
  99.     uppUncompressDataProcInfo = kCStackBased
  100.         | RESULT_SIZE( SIZE_CODE( sizeof( long ) ) )
  101.         | STACK_ROUTINE_PARAMETER( 1, SIZE_CODE( 
  102.                                                             sizeof( unsigned
  103. char *) ) )
  104.         | STACK_ROUTINE_PARAMETER( 2, SIZE_CODE( 
  105.                                                             sizeof( unsigned
  106. char *) ) )
  107.         | STACK_ROUTINE_PARAMETER( 3, SIZE_CODE( 
  108.                                                             sizeof( long ) ) )
  109. };
  110.  
  111. #else
  112.  
  113.  
  114. typedef CompressDataProcPtr             CompressDataUPP;
  115. typedef UncompressDataProcPtr         UncompressDataUPP;
  116. #endif
  117.  
  118. //============================================================
  119. //    Extern Globals
  120. //
  121.  
  122. #ifndef powerc
  123.  
  124. extern CompressDataUPP            myCompressDataUPP;
  125. extern UncompressDataUPP        myUncompressDataUPP;
  126.  
  127. #endif
  128.  
  129. //============================================================
  130. //    Macros
  131. //
  132.  
  133. #if GENERATINGPOWERPC || defined(powerc) || defined (__powerc)
  134.  
  135. #define myCompressData( a, b, c )            CompressData( a, b, c )
  136. #define myUncompressData( a, b, c )    UncompressData( a, b, c )
  137.  
  138. #else
  139.  
  140. #define myCompressData( a, b, c ) \     
  141.                 (*(CompressDataUPP)myCompressDataUPP( a, b, c )
  142. #define myUncompressData( a, b, c  ) \
  143.                 (*(CompressDataUPP)myUncompressDataUPP( a, b, c )
  144.  
  145. #endif
  146.  
  147. //============================================================
  148. //    Prototypes
  149. //
  150.  
  151. long CompressData( unsigned char *inBuffer, unsigned char 
  152.                    *outBuffer, unsigned long inBufferSize );
  153. long UncompressData( unsigned char *inBuffer, unsigned char 
  154.                      *outBuffer, unsigned long inBufferSize );
  155.  
  156. #ifdef __cplusplus
  157. }
  158. #endif
  159.  
  160. Now we define the source file:
  161.  
  162. “the source file”
  163. #include "the header file"
  164.  
  165. #ifdef __cplusplus
  166. extern "C" {
  167. #endif
  168.  
  169. #if GENERATINGPOWERPC || defined(powerc) || defined (__powerc)
  170. #pragma options align=mac68k
  171. #endif
  172.  
  173. #ifdef __CFM68K__
  174. #pragma lib_export on
  175. #endif
  176.  
  177. RoutineDescriptor    CompressDataRD = 
  178.     BUILD_ROUTINE_DESCRIPTOR(     uppCompressDataProcInfo, 
  179.                                                     CompressData );
  180.  
  181. RoutineDescriptor    UncompressDataRD = 
  182.     BUILD_ROUTINE_DESCRIPTOR(     uppUncompressDataProcInfo, 
  183.                                                     UncompressData );
  184.  
  185.  
  186. #ifdef __CFM68K__
  187. #pragma lib_export off
  188. #endif
  189.  
  190. #if GENERATINGPOWERPC || defined(powerc) || defined (__powerc)
  191. #pragma options align=reset
  192. #endif
  193.  
  194. #ifdef __cplusplus
  195. }
  196. #endif
  197.  
  198. Add the shared library we built in Step 1 to this project.
  199. Set the project type to shared library and build the project. We now have a
  200. PowerPC shared library that we want to convert to a resource. (Note: we don’t
  201. export this as a PowerPC code resource with no header, since we would get link
  202. errors for an undefined main entry.)
  203. Open the file up in a resource editor and create a new resource (I use a type
  204. of 'PEF ', but any will do).  Move the PEF code from the data fork into this
  205. resource.  (If your resource editor will not do this, then it is a simple
  206. matter of creating a small application that will do this for you; this
  207. excercise is left for the reader.)
  208. We now have a resource file that we will add to our 68K project.
  209.  
  210. Step 3 – Add 68K support code to your project
  211. Your 68K project needs to have a bit of support code to get the code resource
  212. and load it in as a code fragment.  Add to your code:
  213.  
  214. #include "the header file"
  215.  
  216. We need to declare some globals for the universal procs that will store the
  217. address of the routine descriptors. Add to your code:
  218.  
  219. #ifndef powerc
  220. CompressDataUPP                    myCompressDataUPP;
  221. UncompressDataUPP                myUncompressDataUPP;
  222. #endif
  223.  
  224. The following function takes care of checking for the existence of the CFM and
  225. Mixed Mode managers. We pass it a pointer to a CFragConnectionID variable and a
  226. Handle variable, which we will use later on for clean up.  Add to your code:
  227.  
  228. #ifndef powerc
  229.  
  230. //    SetupPPCNativeCode
  231.  
  232. OSErr SetupPPCNativeCode(     CFragConnectionID *connID, 
  233.                                                 Handle *PEFHandle,
  234.                                                   ResType codeFragmentType, 
  235.                                                 short codeFragmentID )
  236. {
  237.     OSErr                    theErr = noErr;
  238.     long                        templong;
  239.     Str255                    failedFragName;
  240.     
  241.  
  242.     // get PEF container resource from our resource fork
  243.     
  244.     *PEFHandle = ::Get1Resource( codeFragmentType, codeFragmentID );
  245.     theErr = ::ResError();
  246.     
  247. if( !(*PEFHandle) )
  248.     {
  249.         if( theErr )    
  250.             return( theErr );
  251.         else
  252.             return( ::MemError() );
  253.     }
  254.         
  255.     // Check for Mixed Mode Manager and Code Fragment Manager (CFM)
  256.     
  257.     Boolean     hasMixedMode = !Gestalt(    gestaltMixedModeAttr, 
  258.                                                                 &templong );
  259.     Boolean     hasCFM = !Gestalt( gestaltCFMAttr, &templong );
  260.         
  261.     theErr = Gestalt( gestaltSysArchitecture, &templong );
  262.     if( ( theErr ) || 
  263.         ( templong == gestalt68k ) ||
  264.         ( !hasCFM ) ||
  265.         ( !hasMixedMode ) )
  266.     {
  267.         ::ReleaseResource( *PEFHandle );
  268.         return( -1 );
  269.     }
  270.         
  271.     DetachResource( *PEFHandle );
  272.     MoveHHi( *PEFHandle );
  273.     HLock( *PEFHandle );
  274.     
  275.     // Assume this is PowerPC code, so it must be “prepared”
  276.     
  277.     theErr = ::GetMemFragment( (Ptr)**PEFHandle, 0, 0,         
  278.                                 kNewCFragCopy, connID, 0, failedFragName );
  279.     if( theErr )
  280.     {
  281.         DisposeHandle( *PEFHandle );
  282.         return( theErr );
  283.     }
  284.  
  285.     CFragSymbolClass        myClass;
  286.     
  287.     if( !theErr )
  288.         theErr = ::FindSymbol( *connID, 
  289.                                (ConstStr255Param)"\pCompressDataRD", 
  290.                                (Ptr*)&myCompressDataUPP, 
  291.                                &myClass );
  292.     if( !theErr )
  293.         theErr = ::FindSymbol( *connID, 
  294.                                (ConstStr255Param)"\pUncompressDataRD", 
  295.                                (Ptr*)&myUncompressDataUPP, 
  296.                                &myClass );
  297.  
  298.     if( theErr )
  299.     {
  300.         DisposeHandle( *PEFHandle );
  301.         return( theErr );
  302.     }
  303.     
  304.     return( noErr );
  305. }
  306.  
  307. The following function takes the connection id and handle returned from
  308. SetupPPCNativeCode, frees the connection and disposes of the handle.  Add to
  309. your code:
  310.  
  311. //    TearDownPPCNativeCode
  312.  
  313. void TearDownPPCNativeCode( CFragConnectionID connID, Handle PEFHandle )
  314. {
  315.     ::CloseConnection( &connID );
  316.     if( PEFHandle )
  317.         ::DisposeHandle( PEFHandle );
  318. }        
  319.  
  320. #endif
  321.  
  322. Build your 68K project as you normally would and be sure to include the
  323. resource file we created in Step 2 and ensure the the shared library we created
  324. in Step 1 is either in the Extensions folder of the System Folder or in the
  325. same directory as the application.
  326. Here is what you would do the call the PowerPC code from 68K:
  327.  
  328. long PowerPC_Compress( unsigned char *inBuffer, unsigned char 
  329.                        *outBuffer, unsigned long inBufferSize )
  330. {
  331.     #ifndef powerc
  332.     
  333.     // For efficiency you would probably put this call in initialization code.
  334.     // sConnID and sPEFHandle are static globals.
  335.     
  336.     OSErr err = SetupPPCNativeCode(    &sConnID, &sPEFHandle, 
  337.                                                             'PEF ', 128 );
  338.     if( err )
  339.         return( 0 );    // We couldn’t compress anything so return 0
  340.     #endif
  341.     
  342.     long        result = 0;
  343.     
  344.     result = myCompressData( inBuffer, outBuffer, inBufferSize );
  345.     
  346.     #ifndef powerc
  347.     
  348.     // For efficiency you would probably put this call in termination code.
  349.     
  350.     TearDownPPCNativeCode( sConnID, sPEFHandle );
  351.     #endif
  352. }
  353.  
  354. long PowerPC_Uncompress( unsigned char *inBuffer, 
  355.         unsigned char *outBuffer, unsigned long inBufferSize )
  356. {
  357.     #ifndef powerc
  358.     
  359.     // For efficiency you would probably put this call in initialization code.
  360.     // sConnID and sPEFHandle are static globals.
  361.     
  362.     OSErr err = SetupPPCNativeCode(    &sConnID, &sPEFHandle, 
  363.                                                             'PEF ', 128 );
  364.     if( err )
  365.         return( 0 );    // We couldn’t compress anything so return 0
  366.     #endif
  367.     
  368.     long        result = 0;
  369.     
  370.     result = myUncompressData( inBuffer, outBuffer, inBufferSize );
  371.     
  372.     #ifndef powerc
  373.     
  374.     // For efficiency you would probably put this call in termination code.
  375.     
  376.     TearDownPPCNativeCode( sConnID, sPEFHandle );
  377.     #endif
  378. }
  379.  
  380.  
  381. That’s all there is to it.  Enjoy and happy coding.
  382. – Chris Rudolph
  383.  
  384. [BuildRoutineDescriptor() doesn’t work right with CFM68k; use
  385. NewRoutineDescriptor() instead.  BuildRoutineDescriptor() generates code so you
  386. need to call MakeDataExecutable() after it. – sgs]
  387.